/*
 1:
   # Program have modules
   # Auto-install hyperbola
   # Auto-configuration firewall
   # Auto-install virtual machenes (public, private, AnonNet) {public -> internet} {private -> i2p -> internet} {AnonNet -> i2p/yggdrasil} 
   TODO qemu-tui program
   TODO orange pi -tui installer
 2:
   # Init ncurves
   # Create menu
    {Full installation hyperbola}
    {Configrate firewall}
    {Exit}

 3: C++, ncurses, g++, make
 4:file
   # Init ncurves
    > Init
    > raw mode
    > create var ch
    > enable keypad
    > noecho

   # Create menu
    > Create menu window
    > print menu items
    > get user input
      > create loop while(True)
      > Create swithch case
      >

   # User can select in menu
    > Change background to item
*/ 

// #!/bin/bash

// echo "########### Drive mirroring starting at `date` ###########"

// SOURCE=/media/user_name/Master/
// DEST=/media/user_name/Slave/mirror
// rsync -ahvAE --delete --stats $SOURCE $DEST 2>&1 | tee /var/log/drive-mirroring.log

// echo "########### Drive mirroring completed at `date` ###########"

//glibc


#include <cstdlib>
#include <iostream>
#include <ncurses.h> // TUI
#include <fstream>
#include <sys/select.h>
#include <vector>

#include "menu.h"
#include "nftables.h"
#include "arch_linux.h"


// void full_disk_encrypt_install_hyperbola() 
// {
//     const std::string PARTION_LUKS = "/dev/sda4",
//                       ROOT_SIZE = "60G",

//                       DISK_GRUB = "/dev/sdc",                   
//                       PARTION_GRUB = (DISK_GRUB + "1").data(),

//                       PACKAGES = "xenocara-xinit xenocara-server doas alsa-utils zip unzip tar cmus mupdf",
//                       NET_TOOLS = "dhclient net-tools wget curl",
//                       DRIVERS = "xenocara-video-intel mesa",
//                       VIRTUAL_VM_SOFT = "qemu vde2 dnsmasq bridge-utils",
//                       OPTIMAZE_SYSTEM_SOFT = "irqbalance",


//                       TIMEZONE = "/usr/share/zoneinfo/UTC",
//                       HOSTNAME = "qu4rx",

//                       NAME_USER = "user";

//     // Clear diplay
//     system("clear");

//     // Enable internet
//   system("echo \"\n[SET UP INTERNET]\" && sleep 1");
    // system("dhclient -4");

//     // Update system
    // system("echo \"\n[UPDATE]\" && sleep 1");
    // system("pacman -Syu --noconfirm");

//     // Keyboard layout
//     system("clear");
//     system("echo \"\n[SET LOADKEYS TO US]\" && sleep 1");
//     system("loadkeys us");

//     // Install dependencies
//     system("echo \"\n[INSTALL CRYPTSETUP]\" && sleep 1");
//     system("pacman -Syy cryptsetup lvm2 --noconfirm");

//     // Enable service lvm
//     system("clear");
//     system("echo \"\n[ENABLE SEVICES]\" && sleep 2");
//     system("rc-update add dmcrypt boot");
//     system("rc-update add lvm boot");


//     // Enable crypt module
    // system(("modprobe dm-mod"));


//     // Disk configuration
//     system("echo \"\n[PARTION GRUB CONFIGURATION]\" && sleep 2");
//     system(("sfdisk --delete " + DISK_GRUB).data()); 
//     system(("parted " + DISK_GRUB + " mkpart primary 0% 600MB").data());   
//     system(("mkfs.ext2 " + PARTION_GRUB).data());

//     // system("sfdisk -l"); // print partions
//     // sfdisk -l -uM

//     // Format partition with LUKS encryption
//     system("echo \"\n[LUKS Encryption]\" && sleep 2");
//     system(("mkfs.ext4 " + PARTION_LUKS).data());
//     system(("cryptsetup -v --cipher serpent-xts-plain64 --key-size 512 --hash whirlpool --iter-time 500 --use-random --verify-passphrase luksFormat " + PARTION_LUKS).data());

//     // Open encrypted partition
//     system("echo \"[OPEN CRYPT DISK]\" && sleep 2");
//     system(("cryptsetup open " + PARTION_LUKS +" lvm").data());

//     // Create lvm
//     system("echo \"[CONFIGURATE LVM]\" && sleep 2");
//     system("pvcreate /dev/mapper/lvm");

//     // Create lvm group
//     system("vgcreate glvm /dev/mapper/lvm");

//     // Create lvm patrions
//     system("echo \"[CONFIGURATE LVM]\" && sleep 2");
//     system("lvcreate -L 2G glvm -n swapvol");
//     system(("lvcreate -L " + ROOT_SIZE + " glvm -n rootvol").data());
//     system("lvcreate -l +100%FREE glvm -n homevol");

//     // Swap
//     system("echo \"[ENABLE SWAP partion]\" && sleep 2");
//     system("mkswap /dev/mapper/glvm-swapvol");
//     system("swapon /dev/glvm/swapvol");

//     // mkfs
//     system("echo \"[FORMAT PARTIONS]\" && sleep 2");
//     system("mkfs.ext4 /dev/mapper/glvm-rootvol");
//     system("mkfs.ext4 /dev/mapper/glvm-homevol");
//     system(("mkfs.ext2 " + PARTION_GRUB).data());

//     // mount
//     system("echo \">>> [MOUNT PARTIONS]\" && sleep 2");
//     system("mount /dev/glvm/rootvol /mnt");
//     system("mkdir -p /mnt/home");
//     system("mount /dev/glvm/homevol /mnt/home");

//     // boot
//     system("mkdir -p /mnt/boot");
//     system(("mount " + PARTION_GRUB + " /mnt/boot").data());

//     // Install the base system
//     system("clear");
//     system("echo \"\n[INSTALL BASE SYSTEM]\" && sleep 2");
//     system(("pacstrap /mnt base " + PACKAGES + " " + DRIVERS + " " + VIRTUAL_VM_SOFT + " " + NET_TOOLS + " " + OPTIMAZE_SYSTEM_SOFT).data());

//     // Genfstab
//     system("echo \"\n[GENERATE FSTAB]\" && sleep 2");
//     system("echo \"\n[CONFIGURATION SYSTEM]\"");
//     system("genfstab -U -p /mnt >> /mnt/etc/fstab");

//     // Copy the second script (for chroot is work)
//     system("echo \"\n[COPY: install_chroot, variables.txt FOR CHROOT INSTALLATION]\"");
//     system("cp -fv install_chroot /mnt/");
//     system("chmod +x /mnt/install_chroot");

//     // Write variables to file for second script
//     system("rm -f /mnt/variables.txt"); // if file is created after  
//     system(("echo \"" + TIMEZONE + "\" >> /mnt/variables.txt").data());
//     system(("echo \"" + HOSTNAME + "\" >> /mnt/variables.txt").data());
//     system(("echo \"" + NAME_USER + "\" >> /mnt/variables.txt").data());
//     system(("echo \"" + DISK_GRUB + "\" >> /mnt/variables.txt").data());
//     system(("blkid -o value -s UUID " + PARTION_LUKS + ">> /mnt/variables.txt").data());
//     system("blkid -o value -s UUID /dev/glvm/rootvol >> /mnt/variables.txt");

//     // Chroot
//     system("echo \"\n[Chroot]\" && sleep 2");
//     system("arch-chroot /mnt ./install_chroot");
// }


std::vector<std::string> read_From_File_To_Array(std::string file_name, int count_lines) {
    std::ifstream file(file_name);
    std::string line;

    // read line by line and add to array
    std::vector<std::string> items{};

    for (int i{}; i < count_lines; i++) {
        getline(file, line);

        if (line != "")
            items.push_back(line);
    }
    file.close();

    return items;
}
std::string read_line_from_file(std::string file_name) {
    std::ifstream file(file_name);
    std::string line;

    getline(file, line);
    file.close();

    return line;
}

bool check_user_is_root() {
    system("whoami > .whoami");
    std::string user = read_line_from_file(".whoami");

    if (user != "root"){
        system("clear && rm -rf .whoami");
        std::cout << "\n" << "Run as root!" << "\n";

        return false;
    }

    system("rm -rf .whoami");

    return true;
}


bool install_hyperbola() {
    if( !check_user_is_root() ) return 0;

    std::vector<std::string> items = {
        "* Install with Full-Disk-Encryption, GRUB -> PARTION]",
        "* INSTALL with Full-Disk-Encryption, GRUB -> FLASH]"};
    Menu menu_hyperbola("~Hyperbola Linux Intaller~", 15, 65, 0, 0, items);
    menu_hyperbola.setTitleMode(A_BOLD);
    menu_hyperbola.setTitleColors(COLOR_CYAN, COLOR_BLACK);
    menu_hyperbola.setTitlePosition(0, 15);
    menu_hyperbola.drawMenu();
    menu_hyperbola.exit();
    
    // Read disks // TODO tr -d должна выводить что-то кроме disk identifaier and Disklabel type
    system("fdisk -l | grep \"Disk\" > .disks");
    std::vector<std::string> disks = read_From_File_To_Array(".disks", 10);

    // Read pations
    system("sudo sfdisk --list |  awk -F : '/^[/dev/sda*:]/ {print $0}' > .partions");
    std::vector<std::string> partions = read_From_File_To_Array(".partions", 10);

    // Window with disks
    Menu menu_hyperbola_disks("Your disks", 15, 80, 0, 15, disks);
    menu_hyperbola_disks.setTitleMode(A_BOLD);
    menu_hyperbola_disks.setTitleColors(COLOR_GREEN, COLOR_BLACK);
    menu_hyperbola_disks.setTitlePosition(0, 15);
    menu_hyperbola_disks.drawBox();

    // Menu partions
    Menu menu_hyperbola_partions("Select PARTION where install hyperbola", 15, 80, 0, 90+10, partions);
    menu_hyperbola_partions.setTitleMode(A_BOLD);
    menu_hyperbola_partions.setTitleColors(COLOR_GREEN, COLOR_BLACK);
    menu_hyperbola_partions.setTitlePosition(0, 15);
    menu_hyperbola_partions.drawMenu();

    menu_hyperbola_disks.exit();
    menu_hyperbola_partions.exit();
    

     // Menu partions
    // Menu menu_hyperbola_grub_partions("Select DISK where install GRUB", 15, 80, 0, 0, partions);
    // menu_hyperbola_partions.setTitleMode(A_BOLD);
    // menu_hyperbola_partions.setTitleColors(COLOR_YELLOW, COLOR_RED);
    // menu_hyperbola_partions.setTitlePosition(0, 15);
    // menu_hyperbola_partions.drawMenu();
    // menu_hyperbola_partions.exit();

    // Input set_grub_disk

    // Input root size
    // Input swap size


    // select DISK_GRUB (or select Disk or partion for grub)
     
    std::string selected_partion_luks{partions[(long unsigned int)menu_hyperbola_partions.getPointer()], 0, 9};

    std::string
        xorg_pkg = "xenocara-xinit xenocara-server doas",
        drivers_pkg = "xenocara-video-intel mesa",
        security_pkg = "doas",
        audio_pkg = "alsa-utils cmus",
        net_pkg = "dhclient net-tools wget curl",

        optimaze_system_pkg = "irqbalance",
        arhivators_pkg = "zip unzip tar",
        vm_pkg = "virt-manager qemu vde2 dnsmasq bridge-utils libvirt",
        other_pkgs = "mupdf";

    Arch_linux hyperbola;
    hyperbola.set_partion_luks(selected_partion_luks);
    hyperbola.set_size_lvm_volume_root("60G");
    hyperbola.set_size_lvm_volume_swap("2G");
    hyperbola.set_grub_disk("/dev/sdc");
    hyperbola.set_packages(xorg_pkg + " " +
                           drivers_pkg + " " +
                           security_pkg + " " +
                           audio_pkg + " " +
                           net_pkg + " " +
                           optimaze_system_pkg + " " +
                           arhivators_pkg + " " +
                           vm_pkg + " " +
                           other_pkgs);
    hyperbola.set_timezone("UTC");
    hyperbola.set_hostname("n1a7s");
    hyperbola.set_user_name("user");
    hyperbola.set_lvm_group("glvm");
    hyperbola.set_kernel("linux-libre-lts");

    // hyperbola.clear_display();
    // hyperbola.enableInternet();
    // hyperbola.Update();
    // hyperbola.clear_display();
    // hyperbola.loadkeys_us();
    // hyperbola.install_cryptsetup_and_lvm();

    // hyperbola.addService("dmcrypt", "boot");
    // hyperbola.addService("lvm", "boot");

    // hyperbola.modprobe("dm-mod");
    // hyperbola.configurate_disk_for_grub();
    // hyperbola.encrypt_luks_partion();

    // hyperbola.create_lvm();
    // hyperbola.create_lvm_group();
    // hyperbola.create_lvm_volume_swap();

    // hyperbola.create_swap_lvm_partion();
    // hyperbola.enable_swap_lvm_partion();

    // hyperbola.format_lvm_and_grub_partions();
    // hyperbola.mount_lvm_root();
    // hyperbola.mount_lvm_home();
    // hyperbola.mount_lvm_boot();

    // hyperbola.install();
    // hyperbola.generate_fstab();

    // hyperbola.copy_second_script();
    // hyperbola.write_variables_to_file();
    // hyperbola.chroot_and_start_second_script();
    return 0;
} 


bool configrate_nftables() {
    if( !check_user_is_root() ) return 0;
    
    // Get interfaces 
    system("ls -L /sys/class/net/ | awk -F : '/^[A-Za-z0-9]+/ {print $0}' > .interfaces");
    std::vector<std::string> interfaces = read_From_File_To_Array(".interfaces", 10);
    
    // Menu interfaces 
    Menu menu_interfaces("Select interface", 15, 63, 0, 0, interfaces);
    menu_interfaces.setTitleMode(A_BOLD);
    menu_interfaces.setTitleColors(COLOR_CYAN, COLOR_BLACK);
    menu_interfaces.drawMenu();
    menu_interfaces.exit();

    Nftables nft;
    nft.setInteface(interfaces[(long unsigned int)menu_interfaces.getPointer()]);

 

    // Menu nftables
    std::vector<std::string> options = {
        "* Install Nftables",
        "* {ALLOW OUTPUT}",
        "* {BLOCK ALL}",
        "* {VM_GATEWAY_TOR}",
    };
    Menu menu_nftables("NFTABLES", 15, 63, 0, 0, options);
    menu_nftables.setTitleMode(A_BOLD);
    menu_nftables.setTitleColors(COLOR_CYAN, COLOR_BLACK);
    menu_nftables.drawMenu();
    menu_nftables.exit();

    switch (menu_nftables.getSelectedItem()) {
        case 1: {
            // Enable internet
            system("echo \"\n[SET UP INTERNET]\" && sleep 1");
            system("dhclient -4");
            nft.install();
            break;
        }
        case 2: {
            nft.flush_ruleset();

            nft.add_filter_table_ip_v4();
            nft.add_input_rules_in_filter_table_to_ip_v4_to_accept();
            nft.add_forward_rules_in_filter_table_to_ip_v4_to_drop();
            nft.add_output_rules_in_filter_table_to_ip_v4_to_accept();

            nft.add_filter_table_ip_v6();
            nft.add_input_rules_in_filter_table_to_ip_v6_to_drop();
            nft.add_forward_rules_in_filter_table_to_ip_v6_to_drop();
            nft.add_output_rules_in_filter_table_to_ip_v6_to_drop();

            nft.save_ruleset();
            nft.enableLogging();
            nft.print_ruleset();
            break;
        }
        case 3: {
            nft.flush_ruleset();

            nft.add_filter_table_ip_v4();
            nft.add_input_rules_in_filter_table_to_ip_v4_to_drop();
            nft.add_forward_rules_in_filter_table_to_ip_v4_to_drop();
            nft.add_output_rules_in_filter_table_to_ip_v4_to_drop();

            nft.add_filter_table_ip_v6();
            nft.add_input_rules_in_filter_table_to_ip_v6_to_drop();
            nft.add_forward_rules_in_filter_table_to_ip_v6_to_drop();
            nft.add_output_rules_in_filter_table_to_ip_v6_to_drop();

            nft.save_ruleset();
            nft.enableLogging();
            nft.print_ruleset();
            break;
        }
        case 4: {
            // nft.flush_ruleset();
            // TODO SETUP FIREWALL FOR GATEWAY
            break;
        }
    }



    return 0;
}

void install_and_configrate_awesome()
{
    system("doas pacman -Syy --noconfirm");                                  // Update list pkgs
    system("doas pacman -S git make gcc awesome conky yakuake --noconfirm"); // Install awesome conky etc
    system("echo awesome > ~/.xinitrc");                                     // Copy dot files
    system("mkdir ~/.config/awesome && cp -rfv dot_files/awesome/ ~/.config/awesome");                         // Copy dot files
    system("cp -rfv dot_files/.conky/ ~/");                                  // to user-home directory
    system("cp -rfv dot_files/fonts/ ~/");                                   // Copy fonts to user-home directory
    system("fc-cache -Ev");                                                  // and "install" it
    system("cp -rfv dot_files/.bashrc ~/");                                  // Copy bashrc file to user-home directory
    system("git clone https://github.com/ujjwal96/xwinwrap.git && cd xwinwrap && make && sudo make install && cd .. && rm -rf xwinwrap"); // Download script for gif wallpaper
    system("clear && echo \"success! reboot your pc\" ");                    // Message to user
}

int main() {
    std::vector<std::string> menu_items = {
        "> Hyperbola",
        "> Nftables",
        "> Dot files",
        "* Exit"};

    Menu menu("~Hyperbola Linux Intaller~", 15, 65, 0, 0, menu_items);
    menu.setTitleMode(A_BOLD);
    menu.setTitleColors(COLOR_CYAN, COLOR_BLACK);
    menu.setTitlePosition(0, 15);
    menu.drawMenu();
    menu.exit();

    if (menu.getSelectedItem() == 1) install_hyperbola();
    if (menu.getSelectedItem() == 2) configrate_nftables();  
    // if (menu.getSelectedItem() == 3) install_and_configrate_awesome();  

    return 0;
}